home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / WINDOWS / CLIPST.ARJ / CLIPSTAC.CPP < prev    next >
C/C++ Source or Header  |  1992-05-24  |  36KB  |  1,157 lines

  1. // clipstac.cpp RHS 12/15/92
  2.  
  3. #include<stdio.h>
  4. #include<string.h>
  5. #include<memory.h>
  6. #include"windlg.h"
  7. #include"file.h"
  8. #include"cursor.h"
  9. #include"clipbrd.h"
  10. #pragma hdrstop
  11. #include"arraymgr.h"
  12. #include"clipstac.h"
  13. #include"csapi.h"
  14. #include"dynarray.h"
  15.  
  16. #define MAXPATHLEN  144     // Date=8+1 time=6+1 format=8+1 size=6+1
  17. #define DATETIMELEN 36      // 12/13/53 05:15a METAFILE 123456 
  18. #define OWNEROFFSET  32
  19. #define CONTENTOFFSET 42
  20. #define MAXNAMEBUF  (MAXPATHLEN+DATETIMELEN)
  21. #define LastChar(s)     (s[strlen(s)-1])
  22. #define MAXCLIPITEMS    500
  23.  
  24. template<class TYPE>
  25. void DynArray<TYPE>::Delete(TYPE t)
  26.     {
  27.     for(int i = 0; i < num; i++)
  28.         if(t == TArray[i])
  29.             {
  30.             memmove(&TArray[i],&TArray[i+1],sizeof(TYPE)*(size-(i+1)));
  31.             num--;
  32.             return;
  33.             }
  34.     }
  35.  
  36. BOOL ArrayMgr::IsFirstDupe(int index)
  37.     {
  38.     DWORD offset = array[index].offset;
  39.  
  40.     for(int i = 0; i < index; i++)
  41.         if(array[i].offset == offset)
  42.             return FALSE;
  43.     return TRUE;
  44.     }
  45.  
  46. BOOL ArrayMgr::IsDupe(int index)
  47.     {
  48.     return ((array[index].usage > 0) ? TRUE : FALSE);
  49.     }
  50.  
  51. void ArrayMgr::UpdateDupes(int index, DWORD newoffset)
  52.     {
  53.     DWORD oldoffset = array[index].offset;
  54.  
  55.     for(int i = index; i < NumElements(); i++)
  56.         if(array[i].offset == oldoffset)
  57.             array[i].offset = newoffset;
  58.     }
  59.  
  60. void ArrayMgr::UpdateOffsets(DWORD offset)
  61.     {
  62.     for(int i = 0; i < NumElements(); i++)
  63.         array[i].offset += offset;
  64.     }
  65.  
  66. void ArrayMgr::DecrementUsage(DWORD offset)
  67.     {
  68.     for(int i = 0; i < NumElements(); i++)
  69.         if((array[i].offset == offset) && (array[i].usage)) 
  70.             array[i].usage--;
  71.     }
  72.  
  73. void ArrayMgr::SetUsage(DWORD offset, WORD usage)
  74.     {
  75.     for(int i = 0; i < NumElements(); i++)
  76.         if(array[i].offset == offset) 
  77.             array[i].usage = usage;
  78.     }
  79.  
  80.  
  81. typedef struct _clipobject
  82.     {
  83.     DWORD offset;
  84.     WORD format;
  85.     DWORD size;
  86.     char name[MAXNAMEBUF];
  87.     } CLIPOBJECT;
  88.  
  89. typedef struct _header
  90.     {
  91.     int NumElements;
  92.     int MaxElements;
  93.     int Size;
  94.     DWORD LastOffset;
  95.     } HEADER;
  96.  
  97. File StackFile;
  98. Cursor myCursor;
  99.  
  100. char *szAppName = APPNAME;
  101. char *szClipStacDat = "clipstac.dat";
  102. char *szClipStacTemp = "clipstac.$$$";
  103. char *szOwnerUnknown = "(Unknown) ";
  104.  
  105.  
  106. #define MAXFMTS 10
  107. char *fmts[MAXFMTS] = 
  108.     {
  109.     "", // dummy so CF_TEXT (1) can be used to access "CF_TEXT", etc.
  110.     "TEXT     ",  // CF_TEXT
  111.     "BITMAP   ",  // CF_BITMAP      
  112.     "METAFILE ",  // CF_METAFILEPICT
  113.     "SYLK     ",  // CF_SYLK
  114.     "DIF      ",  // CF_DIF         
  115.     "TIFF     ",  // CF_TIFF        
  116.     "OEMTEXT  ",  // CF_OEMTEXT   
  117.     "DIB      ",  // CF_DIB       
  118.     "PALETTE  ",  // CF_PALETTE
  119.     };       
  120.  
  121. char *fmtUnknown = "(Unknown)";
  122.  
  123. #define SC_USER         (0xF000-1)
  124. #define SC_ABOUT        SC_USER
  125. #define SC_AUTOPACK SC_USER-1
  126. #define SC_AUTOLOAD     SC_USER-2
  127.  
  128. char *szAbout = "About ClipStac...";
  129. char *szAutoLoad = "AutoLoad";
  130. char *szMaxItems = "MaxItems";
  131. char *szAutoPack = "AutoPack";
  132.  
  133. BOOL bAutoLoad = FALSE;
  134. BOOL bAutoPack = FALSE;
  135.  
  136. int lbItems = 0;
  137. int MaxItems = MAXCLIPITEMS;
  138.  
  139. #define MAXWINDOWSPARM  256
  140. char outbuf[MAXWINDOWSPARM];
  141.  
  142. BOOL FAR PASCAL _export DialogProc(HWND hDlg, unsigned message, WORD wParam, LONG lParam)
  143.     {
  144.     lParam = lParam;        // turn off compiler warning
  145.  
  146.     switch(message)
  147.         {
  148.         case WM_INITDIALOG:
  149.             SetDlgItemInt(hDlg,4,lbItems,FALSE);
  150.             return TRUE;
  151.  
  152.         case WM_COMMAND:
  153.             if(wParam == IDOK || wParam == IDCANCEL)
  154.                 {
  155.                 EndDialog(hDlg, TRUE);
  156.                 return TRUE;
  157.                 }
  158.             break;
  159.         }
  160.     return FALSE;
  161.     }
  162.  
  163. class ClipStac : public WinDlg
  164.     {
  165. //    HWND hWndNextViewer;
  166.     char ownername[80];
  167.     HANDLE ListBoxHdl, TitleHdl;
  168.     ArrayMgr arrayMgr;
  169.     DynArray<HWND> dynArray;
  170.     HFONT hLBFont, hOldLBFont, hTFont, hOldTFont;
  171.     BOOL inPaste, fmtFound, newFile, inCopy;
  172.     char AppName[MAXPATHLEN];
  173.     HEADER header;
  174.     ClipBoard clp;
  175.     HWND ActiveWindow;
  176.     
  177.     void UpdateListBox(CLIPOBJECT& clobj,WORD usage = 0);
  178. public:
  179.     ClipStac(char *name);
  180.  
  181.     void WMDRAWCLIPBOARD(WinAppMsg& m);
  182.     void WMTIMER(WinAppMsg& m);
  183.     void WMCOMMAND(WinAppMsg& m);
  184.     void WMSYSCOMMAND(WinAppMsg& m);
  185.     void WMCREATE(WinAppMsg& m);
  186.     void WMCHANGECBCHAIN(WinAppMsg& m);
  187.     void WMINITMENU(WinAppMsg& m);
  188.     void WMDESTROY(WinAppMsg& m);
  189.     void WMPAINT(WinAppMsg& m);
  190.     void WMUSER(WinAppMsg& m);
  191.     void WMCTLCOLOR(WinAppMsg& m);
  192.     void WMCLOSE(WinAppMsg& m);
  193.     void WMQUERYENDSESSION(WinAppMsg& m)    {   WMCLOSE(m);  }
  194.     void WMACTIVATE(WinAppMsg& m);
  195.     
  196.     void GetDateTime(CLIPOBJECT& clpobj);
  197.     int Find(LPSTR s);
  198.     void Init(void);
  199.     void ResizeFileHeader(void);
  200.     void PackFile(void);
  201.     DWORD NextSlot(void);
  202.     void SetNextSlot(CLIPOBJECT& clip);
  203.     void UpdateSystemMenu(void);
  204.     BOOL Copy(BOOL notify, int index = -1);
  205.     void AutoLoad(void);
  206.     BOOL Paste(BOOL notify);
  207.     void UpdateHeader(File& f);
  208.     LPSTR Get(int i);
  209.     DWORD FirstRecord(void)         {   return arrayMgr.Size()+sizeof(header);  }
  210.     void InitListBox(void);
  211.     void DeleteItems(void);
  212.     void SetupClipObject(CLIPOBJECT& clip,int format,
  213.         DWORD size, char *ownername, LPSTR lpClipmem = NULL);
  214.     void CopyToTopOfStack(int& index);
  215.     BOOL SelectItem(BOOL notify, int& index);
  216.     BOOL Top(BOOL notify);
  217.     int NumItems(void)              {   return arrayMgr.NumElements();  }
  218.     };
  219.  
  220. void ClipStac::WMINITMENU(WinAppMsg&)
  221.     {
  222.     CheckMenuItem(GetSystemMenu(hWnd,0),
  223.         SC_AUTOLOAD,
  224.         (MF_BYCOMMAND | (bAutoLoad ? MF_CHECKED : MF_UNCHECKED)));
  225.     CheckMenuItem(GetSystemMenu(hWnd,0),
  226.         SC_AUTOPACK,
  227.         (MF_BYCOMMAND | (bAutoPack ? MF_CHECKED : MF_UNCHECKED)));            
  228.     }
  229.  
  230.  
  231. void ClipStac::WMDESTROY(WinAppMsg&)
  232.     {
  233.     clp.QuitViewers();
  234.     PostQuitMessage(0);
  235.     }
  236.  
  237. void ClipStac::UpdateSystemMenu(void)
  238.     {
  239.     HMENU hSysMenu = GetSystemMenu(hWnd,0);
  240.     RemoveMenu(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
  241.     RemoveMenu(hSysMenu, SC_SIZE, MF_BYCOMMAND);
  242.     AppendMenu(hSysMenu, MF_SEPARATOR, 0, NULL);
  243.     AppendMenu(hSysMenu, MF_STRING, SC_ABOUT, szAbout);
  244.     AppendMenu(hSysMenu, MF_STRING, SC_AUTOPACK, szAutoPack);
  245.     AppendMenu(hSysMenu, MF_STRING, SC_AUTOLOAD, szAutoLoad);
  246.     }
  247.  
  248. ClipStac::ClipStac(char *name) : WinDlg(name)
  249.     {
  250.     hLBFont = hOldLBFont = hTFont = hOldTFont = 0;
  251.     ListBoxHdl = TitleHdl = 0;
  252.     ActiveWindow = NULL;
  253. //    hWndNextViewer = NULL;
  254.     SetClassIcon("CLIPSTAC");
  255.     fmtFound = inPaste = newFile = inCopy = FALSE;
  256.     DelWinStyle(WS_VISIBLE);
  257.     bAutoLoad = GetProfileInt(szAppName,szAutoLoad,FALSE);
  258.     bAutoPack = GetProfileInt(szAppName,szAutoPack,FALSE);
  259.     MaxItems = GetProfileInt(szAppName,szMaxItems,MAXCLIPITEMS);
  260.     if((MaxItems > MAXCLIPITEMS) || (MaxItems < 1))
  261.         MaxItems = MAXCLIPITEMS;        // in case user did something ridiculous
  262.     dynArray.Init(10);
  263.  
  264.         // register ClipStac API messages!
  265.     WM_CLIPSTACREGISTER = RegisterWindowMessage(szWM_CLIPSTACREGISTER);
  266.     WM_CLIPSTACPUSH = RegisterWindowMessage(szWM_CLIPSTACPUSH);
  267.     WM_CLIPSTACPOP = RegisterWindowMessage(szWM_CLIPSTACPOP);    
  268.     WM_CLIPSTACFIND = RegisterWindowMessage(szWM_CLIPSTACFIND);
  269.     WM_CLIPSTACGET = RegisterWindowMessage(szWM_CLIPSTACGET);
  270.     WM_CLIPSTACEXIT = RegisterWindowMessage(szWM_CLIPSTACEXIT);
  271.     WM_CLIPSTACDEREGISTER = RegisterWindowMessage(szWM_CLIPSTACDEREGISTER);
  272.     WM_CLIPSTACNUMITEMS = RegisterWindowMessage(szWM_CLIPSTACNUMITEMS);
  273.     }
  274.  
  275.  
  276. DWORD ClipStac::NextSlot(void)
  277.     {
  278.     DWORD retval = arrayMgr.LastOffset();
  279.     if(retval == 0L)
  280.         return arrayMgr.Size()+sizeof(header);
  281.     return (retval+sizeof(CLIPOBJECT));
  282.     }
  283.  
  284. void ClipStac::SetNextSlot(CLIPOBJECT& clip)
  285.     {
  286.     DWORD newoffset = 
  287.         (clip.offset+clip.size+sizeof(CLIPOBJECT)+
  288.         (clip.format == CF_BITMAP ? sizeof(BITMAP) : 0L));
  289.     if(arrayMgr.LastOffset() < newoffset)
  290.         arrayMgr.LastOffset(newoffset);
  291.     }
  292.  
  293.  
  294.     
  295. void ClipStac::WMCHANGECBCHAIN(WinAppMsg& m)
  296.     {      // viewer list has changed
  297.     if(m.wParam == clp.NextViewer)    // our 'next' is removing itself
  298.         clp.NextViewer = LOWORD(m.lParam);
  299.     else if(clp.NextViewer) // not our 'next', tell our 'next'
  300.         SendMessage(clp.NextViewer,m.msg,m.wParam,m.lParam);
  301.     }
  302.  
  303. void ClipStac::AutoLoad(void)
  304.     {
  305.     char *p;
  306.  
  307.     GetProfileString("windows","load","",outbuf,sizeof(outbuf));
  308.     strupr(outbuf);
  309.  
  310.     bAutoLoad = !bAutoLoad;
  311.  
  312.         // if Auto Load is selected and app name is not in LOAD= list
  313.     if(bAutoLoad && !strstr(outbuf,AppName))
  314.         {
  315.         strcpy(outbuf,AppName);               // put WinColor in buffer
  316.         strcat(outbuf," ");                     // add blank and name to it
  317.         p = &LastChar(outbuf);                  // goto last character
  318.         p++;                                    // set to the NULL
  319.                                                 // append LOAD= list
  320.         GetProfileString("windows","load","",p,sizeof(outbuf)-(p-outbuf));
  321.         WriteProfileString("windows","load",outbuf);
  322.         }
  323.         // if Auto Load is not selected and app name is in LOAD= list
  324.     if(!bAutoLoad && (p = strstr(outbuf,AppName)))
  325.         {
  326.         *p = '\0';                              // NULL at start of appname
  327.         p += strlen(AppName);                 // move past appname
  328.         strcat(outbuf,p);                       // copy everybody up
  329.         WriteProfileString("windows","load",outbuf);
  330.         }
  331.     }
  332.  
  333. BOOL ClipStac::Paste(BOOL notify)
  334.     {
  335.     inPaste = TRUE;
  336.     fmtFound = FALSE;
  337.     HWND hWndTemp = clp.NextViewer;
  338.     clp.NextViewer = 0;
  339.     SendMsg(WM_DRAWCLIPBOARD);
  340.     clp.NextViewer = hWndTemp;
  341.     inPaste = FALSE;
  342.     if(notify && !fmtFound)
  343.         MessageBox(hWnd,"No supported formats found or Clipboard is empty!",
  344.             szAppName,MB_OK);
  345.     return fmtFound;
  346.     }
  347.  
  348. void ClipStac::CopyToTopOfStack(int& index)
  349.     {
  350.     CLIPOBJECT clobj;
  351.     char name[MAXNAMEBUF];
  352.     SendMessage(ListBoxHdl,LB_GETTEXT,index,(LONG)(LPSTR)name);
  353.     char *p,*q;
  354.     p = &name[OWNEROFFSET];
  355.     //q = &name[CONTENTOFFSET];
  356.     SetupClipObject(clobj,arrayMgr[index]->format,arrayMgr[index]->size,p);
  357.     clobj.offset = arrayMgr[index]->offset;
  358.     UpdateListBox(clobj,arrayMgr[index]->usage+1);
  359.     index++;
  360.     }
  361.  
  362. BOOL ClipStac::SelectItem(BOOL notify, int& index)
  363.     {
  364.     index = SendMessage(ListBoxHdl,LB_GETCURSEL,0,0L);
  365.     if(index == LB_ERR || !arrayMgr.IsValid(index))
  366.         {
  367.         if(notify)
  368.             MessageBox(hWnd,"No item selected!",szAppName,MB_OK);
  369.         return FALSE;
  370.         }
  371.     return TRUE;
  372.     }
  373.  
  374. BOOL ClipStac::Top(BOOL notify)
  375.     {
  376.     int index;
  377.     if(!SelectItem(notify,index))
  378.         return FALSE;
  379.     CopyToTopOfStack(index);
  380.     return TRUE;
  381.     }
  382.  
  383. BOOL ClipStac::Copy(BOOL notify, int index)
  384.     {
  385.     BOOL retval = FALSE;
  386.  
  387.     if(index == -1)
  388.         if(!SelectItem(notify,index))
  389.             return FALSE;
  390.     CopyToTopOfStack(index);
  391.  
  392.     HANDLE hMemory;
  393.     if(arrayMgr[index]->format == CF_BITMAP)
  394.         {
  395.         BITMAP bitmap;
  396.         StackFile.ReadAt(arrayMgr[index]->offset+sizeof(CLIPOBJECT),
  397.             (WORD)sizeof(BITMAP),&bitmap);
  398.         HANDLE hBits = GlobalAlloc(GHND,arrayMgr[index]->size);
  399.         bitmap.bmBits = GlobalLock(hBits);
  400.         StackFile.ReadAt(arrayMgr[index]->offset+sizeof(CLIPOBJECT)+sizeof(BITMAP),
  401.             arrayMgr[index]->size,bitmap.bmBits);
  402.         hMemory = CreateBitmapIndirect(&bitmap);
  403.         GlobalUnlock(hBits);
  404.         GlobalFree(hBits);
  405.         }
  406.     else
  407.         {
  408.         hMemory = GlobalAlloc(GHND,arrayMgr[index]->size);
  409.         LPSTR lpClipmem = GlobalLock(hMemory);
  410.         StackFile.ReadAt(arrayMgr[index]->offset+sizeof(CLIPOBJECT),
  411.             arrayMgr[index]->size,(void far *)lpClipmem);
  412.         GlobalUnlock(hMemory);
  413.         }
  414.  
  415.     if(!clp.Open())
  416.         {
  417.         if(notify)
  418.             MessageBox(hWnd,"Cannot open Clipboard!",szAppName,MB_OK);
  419.         }
  420.     else
  421.         {
  422.         inCopy = TRUE;
  423.         clp.Empty();
  424.         clp.SetData(arrayMgr[index]->format,hMemory);
  425.         clp.Close();
  426.         retval = TRUE;
  427.         }
  428.     return retval;
  429.     }
  430.  
  431. void ClipStac::WMPAINT(WinAppMsg&)
  432.     {              
  433.     PAINTSTRUCT ps;
  434.     BeginPaint(hWnd, &ps);
  435.     EndPaint(hWnd, &ps);
  436.     }
  437.  
  438.         char message[50];
  439. void ClipStac::WMUSER(WinAppMsg& m)
  440.     {
  441.     if(m.msg == WM_CLIPSTACREGISTER)   // returns our hWnd
  442.         {   // ClipStac's hWnd in LOWORD, put user's hWnd in HIWORD 
  443.         LONG l = MAKELONG(hWnd,m.wParam);
  444.         PostMessage(m.wParam,WM_CLIPSTACREGISTER,0,l);
  445.         dynArray.Add(m.wParam);
  446.         m.userMsgUsed = TRUE;
  447.         }
  448.     if(m.msg == WM_CLIPSTACPUSH)      // returns FALSE if unsuccessful
  449.         {
  450.         m.msgRetVal = Paste(FALSE);
  451.         m.userMsgUsed = TRUE;
  452.         }
  453.     if(m.msg == WM_CLIPSTACPOP)       // returns FALSE if unsuccessful
  454.         {
  455.         m.msgRetVal = Copy(FALSE,m.wParam);
  456.         m.userMsgUsed = TRUE;
  457.         }
  458.     if(m.msg == WM_CLIPSTACFIND)
  459.         {
  460.         m.userMsgUsed = TRUE;
  461.         m.msgRetVal = Find((LPSTR)m.lParam);
  462.         }
  463.     if(m.msg == WM_CLIPSTACGET)
  464.         {
  465.         m.userMsgUsed = TRUE;
  466.         m.msgRetVal = (LONG)Get(m.wParam);
  467.         }
  468.     if(m.msg == WM_CLIPSTACDEREGISTER)
  469.         {
  470.         m.userMsgUsed = TRUE;
  471.         dynArray.Delete(m.wParam);
  472.         }
  473.     if(m.msg == WM_CLIPSTACNUMITEMS)
  474.         {
  475.         m.userMsgUsed = TRUE;
  476.         m.msgRetVal = NumItems();
  477.         }
  478.     }
  479.  
  480. void ClipStac::WMCTLCOLOR(WinAppMsg& m)
  481.     {
  482.     if(!ListBoxHdl && (HIWORD(m.lParam) == CTLCOLOR_LISTBOX))
  483.         {
  484.         ListBoxHdl = LOWORD(m.lParam);
  485.         SetTimer(hWnd,1,100,NULL);
  486.         }
  487.     if(!TitleHdl && (HIWORD(m.lParam) == CTLCOLOR_STATIC))
  488.         {
  489.         WORD iD = GetDlgCtrlID(LOWORD(m.lParam));
  490.         if(iD == IDM_TITLE)
  491.             {
  492.             TitleHdl = LOWORD(m.lParam);
  493.             SetTimer(hWnd,2,100,NULL);
  494.             }
  495.         }
  496.     DefWinProc(m);
  497.     }
  498.  
  499. void ClipStac::UpdateHeader(File& f)
  500.     {
  501.     header.NumElements = arrayMgr.NumElements();
  502.     header.MaxElements = arrayMgr.MaxElements();
  503.     header.Size = arrayMgr.Size();
  504.     header.LastOffset = arrayMgr.LastOffset();
  505.  
  506.     f.WriteAt(0L,sizeof(header),&header);
  507.     f.WriteAt(0L+sizeof(header),
  508.         (WORD)arrayMgr.Size(),arrayMgr.Array());
  509.     }
  510.  
  511. void ClipStac::WMCLOSE(WinAppMsg&)
  512.     {
  513.     myCursor(WAIT);
  514.     if(StackFile.IsOpen())
  515.         {
  516.         UpdateHeader(StackFile);
  517.         StackFile.Close();
  518.         }
  519.     if(ListBoxHdl)
  520.         {
  521.         HDC hDC = GetDC(ListBoxHdl);
  522.         SelectObject(hDC,hOldLBFont);
  523.         ReleaseDC(ListBoxHdl,hDC);
  524.         SendMessage(ListBoxHdl,WM_SETFONT,hOldLBFont,FALSE);
  525.         DeleteObject(hLBFont);
  526.         }
  527.  
  528.     if(TitleHdl)
  529.         {
  530.         HDC hDC = GetDC(TitleHdl);
  531.         SelectObject(hDC,hOldTFont);
  532.         ReleaseDC(TitleHdl,hDC);
  533.         SendMessage(TitleHdl,WM_SETFONT,hOldTFont,FALSE);
  534.         DeleteObject(hTFont);
  535.         }
  536.  
  537.     WriteProfileString(szAppName,szAutoLoad,(bAutoLoad ? "1" : "0"));
  538.     WriteProfileString(szAppName,szAutoPack,(bAutoPack ? "1" : "0"));
  539. #ifdef OLD
  540.     char buf[20];
  541.     sprintf(buf,"%d",MaxItems);
  542.     WriteProfileString(szAppName,szMaxItems,buf);
  543. #endif
  544.     for(int i = 0; i < dynArray.NumItems(); i++)
  545.         PostMessage(dynArray[i],WM_CLIPSTACEXIT,hWnd,0L);
  546.     myCursor(ARROW);
  547.     DestroyWindow(hWnd);
  548.     }
  549.  
  550. LPSTR ClipStac::Get(int i)
  551.     {
  552.     CLIPOBJECT clobj;
  553.  
  554.     if(arrayMgr.IsValid(i))
  555.         {
  556.         StackFile.ReadAt(arrayMgr[i]->offset,sizeof(clobj),&clobj);
  557.         return (LPSTR)clobj.name;
  558.         }
  559.     return (LPSTR)NULL;
  560.     }
  561.  
  562. int ClipStac::Find(LPSTR s)
  563.     {
  564.     int i;
  565.     CLIPOBJECT clobj;
  566.     
  567.     for(i = 0; i < arrayMgr.NumElements(); i++)
  568.         {
  569.         StackFile.ReadAt(arrayMgr[i]->offset,sizeof(clobj),&clobj);
  570.         if(_fstrstr(clobj.name,s))
  571.             return i;
  572.         }
  573.     return -1;
  574.     }
  575.     
  576. void ClipStac::WMCREATE(WinAppMsg& m)
  577.     {
  578.     clp.SethWnd(hWnd);
  579.  
  580.     char dir[MAXPATHLEN];
  581.     BOOL tried_already = FALSE;
  582.  
  583.     UpdateSystemMenu();
  584.  
  585.     GetModuleFileName(GetClassWord(hWnd,GCW_HMODULE),AppName, MAXPATHLEN-1);
  586.     GetWindowsDirectory(dir,sizeof(dir));
  587.     strcat(dir,"\\");
  588.     strcat(dir,szClipStacDat);
  589.     StackFile.SetName(dir);
  590. tryopen:
  591.     if(!StackFile.Open(OF_READWRITE /* | OF_SHARE_EXCLUSIVE */))
  592.         {
  593.         if(!tried_already)
  594.             {
  595.             if(MessageBox(hWnd,"Unable to open CLIPSTAC.DAT...create it?",
  596.                 szAppName,MB_YESNO | MB_ICONQUESTION) == IDYES)
  597.                 {
  598.                 if(StackFile.Create(0))
  599.                     {
  600.                     newFile = TRUE;
  601.                     StackFile.Close();
  602.                     tried_already = TRUE;
  603.                     goto tryopen;
  604.                     }
  605.                 else
  606.                     MessageBox(hWnd,"Unable to create CLIPSTAC.DAT...terminating.",
  607.                         szAppName,MB_OK);
  608.                 }
  609.             else
  610.                 MessageBox(hWnd,"Unable to open CLIPSTAC.DAT...terminating",
  611.                     szAppName, MB_OK);
  612.             }
  613.         SendMsg(WM_CLOSE);
  614.         m.msgRetVal = -1L;
  615.         return;
  616.         }
  617.     if(StackFile.Size() == 0L)
  618.         newFile = TRUE;
  619.     SetFocus(GetDlgItem(hWnd, IDM_COPY));
  620.     }
  621.  
  622. void ClipStac::GetDateTime(CLIPOBJECT& clpobj)
  623.     {
  624.     BYTE hour, minutes, pm, month, day, year;
  625.  
  626.     _AH = 0x2A;
  627.     asm int 0x21;
  628.  
  629.     month = _DH;
  630.     day = _DL;
  631.     year = _CX-1900;
  632.  
  633.     _AH = 0x2C;
  634.     asm int 0x21;
  635.     hour = _CH;
  636.     minutes = _CL;
  637. //    seconds = _DH;
  638. //    hundreds = _DL;
  639.  
  640.     pm = FALSE;
  641.  
  642.     if(hour >= 12)
  643.         {
  644.         pm = TRUE;
  645.         if(hour > 12)
  646.             hour -= 12;
  647.         }
  648.     if(!hour)
  649.         hour = 12;
  650.     sprintf(clpobj.name,"%02d/%02d/%02d %02d:%02d%c ",
  651.         month,day,year,hour,minutes,(pm ? 'p' : 'a'));
  652.     }
  653.  
  654. void ClipStac::WMCOMMAND(WinAppMsg& m)
  655.     {
  656.     switch(m.wParam)
  657.         {
  658.         case IDM_LISTBOX:
  659.             if(HIWORD(m.lParam) == LBN_DBLCLK)
  660.                 SendMsg(WM_COMMAND,IDM_COPY);
  661.             break;
  662.  
  663.         case IDM_COPY:
  664.             Copy(TRUE);
  665.             break;
  666.  
  667.         case IDM_PASTE:
  668.             Paste(TRUE);
  669.             break;
  670.  
  671.         case IDM_TOP:
  672.             Top(TRUE);
  673.             break;
  674.  
  675.         case IDM_DELETE:
  676.             {
  677.             int index;
  678.             if(SelectItem(TRUE,index))
  679.                 {
  680.                 SendMessage(ListBoxHdl,LB_DELETESTRING,index,0L);
  681.                 arrayMgr.Delete(index);
  682.                 int count = SendMessage(ListBoxHdl,LB_GETCOUNT,0,0L);
  683.                 if((count > 0) && (count != index))
  684.                     SendMessage(ListBoxHdl,LB_SETCURSEL,index,0L);
  685.                 }
  686.             }
  687.             break;
  688.             
  689.         case IDM_HELP:
  690.             {
  691. #if defined(__BORLANDC__)
  692.             DialogBox(GetInstance(), "HELP", hWnd, (FARPROC)DialogProc);
  693. #else
  694.             FARPROC lpDlgProc = MakeProcInstance((FARPROC)DialogProc,GetInstance());
  695.             DialogBox(GetInstance(), "HELP", hWnd, lpDlgProc);
  696.             FreeProcInstance(lpDlgProc);
  697. #endif
  698.             SetFocus(GetDlgItem(hWnd,IDM_HELP));
  699.             }
  700.             break;
  701.  
  702.         case IDM_PACK:
  703.             if(MessageBox(hWnd,"Packing CLIPSTAC.DAT may take some time...proceed?",szAppName,
  704.                 MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OKCANCEL) == IDOK)
  705.                 {
  706.                 myCursor(WAIT);
  707.                 int index;
  708.                 SelectItem(FALSE,index);
  709.                 PackFile();
  710.                 DeleteItems();
  711.                 InitListBox();
  712.                 if(index > 0)
  713.                     SendMessage(ListBoxHdl,LB_SETCURSEL,index,0L);                
  714.                 myCursor(ARROW);
  715.                 }
  716.             break;
  717.         }
  718.     }
  719.  
  720.  
  721. void ClipStac::UpdateListBox(CLIPOBJECT& clobj,WORD usage)
  722.     {
  723.     int index, cursel;
  724.     cursel = SendDlgItemMessage(hWnd,IDM_LISTBOX,LB_GETCURSEL,0,0L);
  725.  
  726.     if((index = SendDlgItemMessage(hWnd,IDM_LISTBOX,LB_INSERTSTRING,
  727.             0,(LONG)(LPSTR)clobj.name)) < 0)
  728.         MessageBox(hWnd,"Unable to insert data into List Box!",szAppName,MB_OK);
  729.     else
  730.         {
  731.         while(SendDlgItemMessage(hWnd,IDM_LISTBOX,LB_GETCOUNT,0,0L) > MaxItems)
  732.             SendDlgItemMessage(hWnd,IDM_LISTBOX,LB_DELETESTRING,MaxItems,0L);
  733.  
  734.         arrayMgr.Insert(clobj.offset,clobj.format,clobj.size,usage);
  735.         UpdateHeader(StackFile);
  736.         if(IsIconic(hWnd))
  737.             InvalidateRect(hWnd,NULL,TRUE);
  738.         }
  739.     if(index > 0)
  740.         MessageBox(hWnd,"Insert index not 0!",szAppName,MB_OK);
  741.     if(cursel != LB_ERR)
  742.         SendDlgItemMessage(hWnd,IDM_LISTBOX,LB_SETCURSEL,cursel+1,0L);
  743.     }
  744.  
  745.  
  746. void ClipStac::SetupClipObject(CLIPOBJECT& clobj,int format,
  747.     DWORD size, char *ownername,LPSTR text)
  748.     {
  749.     memset(&clobj,0,sizeof(clobj));
  750.     clobj.format = format;
  751.     clobj.size = size;
  752.     GetDateTime(clobj);
  753.     if(format >= MAXFMTS)
  754.         strcat(clobj.name,fmtUnknown);
  755.     else
  756.         strcat(clobj.name,fmts[format]);
  757.     char buf[20];
  758.     sprintf(buf,"%6lu ",clobj.size);
  759.     strcat(clobj.name,buf);
  760.     if(!text)
  761.         strcat(clobj.name,ownername);
  762.     else
  763.         {
  764.     char *p = strrchr(ownername,'\\');
  765.     if(p && p < ownername+OWNEROFFSET)
  766.         {
  767.         p++;
  768.         char *q = strchr(p,'.');
  769.         if(q)
  770.             {
  771.             while(q < p+10)
  772.                 *q++ = ' ';
  773.             *q = '\0';
  774.             }
  775.         }
  776.     else
  777.         p = ownername;
  778.     strcat(clobj.name,p);
  779.     if(format == CF_TEXT || format == CF_OEMTEXT)
  780.         {
  781.         strcat(clobj.name,"\"");
  782.         _fstrncpy(&clobj.name[7+DATETIMELEN],text,MAXPATHLEN-11);
  783.         }
  784.     else
  785.         memset(&clobj.name[6+DATETIMELEN],'.',MAXPATHLEN-11);
  786.         }
  787.     }
  788.  
  789. void ClipStac::WMACTIVATE(WinAppMsg& m)
  790.     {
  791.     if(!m.wParam)            // window is inactive, save focus
  792.         ActiveWindow = GetFocus();
  793.     else                    // window is being activated, set focus
  794.         {
  795.         if(ActiveWindow)
  796.             SetFocus(ActiveWindow);
  797.         else
  798.             SetFocus(GetDlgItem(hWnd, IDM_COPY));
  799.         }
  800.     }
  801.  
  802. void ClipStac::WMDRAWCLIPBOARD(WinAppMsg& m)
  803.     {
  804.     if(clp.NextViewer)      // notify next viewer
  805.         SendMessage(clp.NextViewer, m.msg, m.wParam, m.lParam);
  806.     if(inCopy)
  807.         {
  808.         inCopy = FALSE;
  809.         DefWinProc(m);
  810.         return;
  811.         }
  812.            // clipboard contents have changed
  813.     if(!inPaste && !clp.GetOwner())
  814.         {
  815.         DefWinProc(m);
  816.         return;
  817.         }
  818.  
  819.     if(!inPaste)
  820.         {
  821.         WORD hModule = GetClassWord(clp.GetOwner(),GCW_HMODULE);
  822.         GetModuleFileName(hModule,ownername,sizeof(ownername)-1);
  823.         }
  824.     else
  825.         strcpy(ownername,szOwnerUnknown);
  826.  
  827.     int format;
  828.     if(!clp.Open())
  829.         MessageBox(hWnd,"Cannot open Clipboard!",szAppName,MB_OK);
  830.     else
  831.         {
  832.         myCursor(WAIT);
  833.         HANDLE hBitmap;
  834.         BITMAP bitmap;
  835.         DWORD bmpSize;
  836.         
  837.         for(format = 0; format = clp.EnumFormats(format) ; )
  838.             {
  839.             switch(format)
  840.                 {
  841.                 case CF_BITMAP:
  842.                     {
  843.                     hBitmap = clp.GetData(format);
  844.                     if(hBitmap)
  845.                         {
  846.                         bitmap;
  847.                         GetObject(hBitmap,sizeof(BITMAP),(LPSTR)&bitmap);
  848.                         bmpSize = (DWORD)bitmap.bmWidthBytes * bitmap.bmHeight * bitmap.bmPlanes;
  849.                         }
  850.                     }
  851.                     // fall thru
  852.                 case CF_TEXT:
  853.                 case CF_SYLK:
  854.                 case CF_DIF:
  855.                 case CF_OEMTEXT:
  856.                 case CF_DIB:
  857.                     {
  858.                     fmtFound = TRUE;
  859.                     HANDLE hClipMemory = (format == CF_BITMAP ) ? hBitmap :
  860.                         clp.GetData(format);
  861.                     if(hClipMemory)
  862.                         {
  863.                         CLIPOBJECT clobj;
  864.  
  865.                         {
  866.                         if(format == CF_TEXT || format == CF_OEMTEXT)
  867.                             {
  868.                             LPSTR lpClipmem = GlobalLock(hClipMemory);
  869.                             SetupClipObject(clobj,format,
  870.                                 (format == CF_BITMAP) ? bmpSize : GlobalSize(hClipMemory),
  871.                                 ownername, lpClipmem);
  872.                             GlobalUnlock(hClipMemory);
  873.                             }
  874.                         else
  875.                             SetupClipObject(clobj,format,
  876.                                 (format == CF_BITMAP) ? bmpSize : GlobalSize(hClipMemory),
  877.                                 ownername, (LPSTR)ownername);
  878.                         }
  879.  
  880.                         StackFile.Offset(NextSlot());
  881.                         clobj.offset = StackFile.CurPosition();
  882.                         StackFile.WriteAt(clobj.offset,(WORD)sizeof(CLIPOBJECT),&clobj);
  883.  
  884.                         if(format == CF_BITMAP)
  885.                             {
  886.                             StackFile.WriteAt(clobj.offset+sizeof(CLIPOBJECT),
  887.                                 (WORD)sizeof(BITMAP),&bitmap);
  888.                             HANDLE hBits = GlobalAlloc(GHND, bmpSize);
  889.                             LPSTR lpClipmem = GlobalLock(hBits);
  890.                             GetBitmapBits(hBitmap,bmpSize,lpClipmem);
  891.                             StackFile.WriteAt(clobj.offset+sizeof(CLIPOBJECT)+sizeof(BITMAP),
  892.                                 bmpSize,lpClipmem);
  893.                             GlobalUnlock(hBits);
  894.                             GlobalFree(hBits);
  895.                             }
  896.                         else
  897.                             {
  898.  
  899.                             LPSTR lpClipmem = GlobalLock(hClipMemory);
  900.                             StackFile.WriteAt(clobj.offset+sizeof(CLIPOBJECT),
  901.                                 clobj.size,(void far *)lpClipmem);
  902.                             GlobalUnlock(hClipMemory);
  903.                             }
  904.                         UpdateListBox(clobj);
  905.                         SetNextSlot(clobj);
  906.                         UpdateHeader(StackFile);
  907.                         }
  908.                     }
  909.                     break;
  910.                 default:
  911.                     break;
  912.                 }
  913.             }
  914.         clp.Close();
  915.         myCursor(ARROW);
  916.         }
  917.     }
  918.  
  919. void ClipStac::WMTIMER(WinAppMsg& m)
  920.     {
  921.     KillTimer(hWnd,m.wParam);
  922.     switch(m.wParam)
  923.         {
  924.         case 2:
  925.             {
  926.             HDC hDC = GetDC(TitleHdl);
  927.             hTFont = GetStockObject(SYSTEM_FIXED_FONT);
  928.             hOldTFont = SelectObject(hDC,hTFont);
  929.             ReleaseDC(TitleHdl,hDC);
  930.             SendMessage(TitleHdl,WM_SETFONT,hTFont,TRUE);
  931.             }
  932.             break;
  933.  
  934.         case 1:
  935.             {
  936.             HDC hDC = GetDC(ListBoxHdl);
  937.             hLBFont = GetStockObject(SYSTEM_FIXED_FONT);
  938.             hOldLBFont = SelectObject(hDC,hLBFont);
  939.             ReleaseDC(ListBoxHdl,hDC);
  940.             SendMessage(ListBoxHdl,WM_SETFONT,hLBFont,FALSE);
  941.             Init();
  942.             }
  943.             break;
  944.         }
  945.     }
  946.  
  947.  
  948. void ClipStac::ResizeFileHeader(void)
  949.     {
  950.     WORD oldMax = arrayMgr.MaxElements();       // get original array size
  951.     DWORD firstOffset = FirstRecord();          // get *before* resizing the array
  952.     if(!arrayMgr.ReSize(MaxItems))              // if re-alloc fails, go with what
  953.         MaxItems = arrayMgr.MaxElements();      // we have
  954.  
  955.     if(oldMax < MaxItems)                       // if array was expanded
  956.         {
  957.         char dir[MAXPATHLEN];
  958.         GetWindowsDirectory(dir,sizeof(dir));
  959.         strcat(dir,"\\");
  960.         strcat(dir,szClipStacTemp);             // create C:\WINDOWS\CLIPSTAC.$$$ name
  961.  
  962.         File TempFile(dir);                     // create temp File object
  963.         TempFile.Create(0);                     // create the file
  964.         arrayMgr.UpdateOffsets(FirstRecord()-firstOffset); // after re-sizing
  965.         UpdateHeader(TempFile);                 // write the new header to the file
  966.         TempFile.Append(StackFile,firstOffset); // tack on remainder of org file
  967.         TempFile.Close();                       // close 'em
  968.         StackFile.Close();
  969.         StackFile.Delete();                     // delete the old guy
  970.         TempFile.Rename(StackFile.GetName());   // rename the disk file
  971.         StackFile.Open(OF_READWRITE);           // re-open it 
  972.         }
  973.     else                                        // if array shrunk
  974.         UpdateHeader(StackFile);
  975.     }
  976.     
  977. void ClipStac::PackFile(void)
  978.     {
  979. #ifdef OLD
  980.     DWORD curroffset = FirstRecord();
  981.     WORD compress = FALSE;
  982.     for(int i = arrayMgr.NumElements()-1 ; i >= 0; i--) // for each item in array
  983.         {                                   // calculate it's true size
  984.         if(arrayMgr.IsDupe(i,arrayMgr[i]->offset))  // if already copied,
  985.             continue;                               // don't copy it
  986.         DWORD size = arrayMgr[i]->size + sizeof(CLIPOBJECT);
  987.         if(arrayMgr[i]->format == CF_BITMAP)
  988.             size += sizeof(BITMAP);        
  989.         if(arrayMgr[i]->offset != curroffset)    // if not at the right offset
  990.             {                                       // copy it to new location
  991.             StackFile.CopyBytes(curroffset,arrayMgr[i]->offset,size);
  992.             arrayMgr[i]->offset = curroffset;    // reset offset in header
  993.             compress = TRUE;
  994.             }
  995.         curroffset += size;                 // set for next location in file
  996.         }
  997.         
  998.     if(!compress)
  999.         return;        
  1000.     UpdateHeader(StackFile);                // write the header
  1001.     char dir[MAXPATHLEN];
  1002.     GetWindowsDirectory(dir,sizeof(dir));
  1003.     strcat(dir,"\\");
  1004.     strcat(dir,szClipStacTemp);             // create C:\WINDOWS\CLIPSTAC.$$$ name
  1005.  
  1006.     File TempFile(dir);                     // create temp file object     
  1007.     TempFile.Create(0);
  1008.     TempFile.Append(StackFile,0,curroffset);
  1009.     TempFile.Close();                       // close 'em
  1010.     StackFile.Close();
  1011.     StackFile.Delete();                     // delete the old guy
  1012.     TempFile.Rename(StackFile.GetName());   // rename the disk file
  1013.     StackFile.Open(OF_READWRITE);           // re-open it     
  1014. #else
  1015.     char dir[MAXPATHLEN];
  1016.     GetWindowsDirectory(dir,sizeof(dir));
  1017.     strcat(dir,"\\");
  1018.     strcat(dir,szClipStacTemp);             // create C:\WINDOWS\CLIPSTAC.$$$ name
  1019.  
  1020.     File TempFile(dir);                     // create temp file object     
  1021.     TempFile.Create(0);
  1022.     DWORD tempOffset = FirstRecord();
  1023.     HANDLE hMem = GlobalAlloc(GHND,0xffff);
  1024.     LPSTR buffer = GlobalLock(hMem);
  1025.  
  1026.     TempFile.Append(StackFile,0,tempOffset,buffer);
  1027.  
  1028.     for(int i = 0; i < arrayMgr.NumElements() ; i++) // for each item in array
  1029.         {
  1030.         if(arrayMgr.IsDupe(i))              // if dupe
  1031.             if(!arrayMgr.IsFirstDupe(i))    // but a subsequent one,
  1032.                 continue;
  1033.                                             // calculate it's true size
  1034.         DWORD size = arrayMgr[i]->size + sizeof(CLIPOBJECT);
  1035.         if(arrayMgr[i]->format == CF_BITMAP)
  1036.             size += sizeof(BITMAP);         // if bitmap, add size of BITMAP
  1037.  
  1038.         TempFile.Append(StackFile,arrayMgr[i]->offset,size+arrayMgr[i]->offset,buffer);
  1039.  
  1040.         if(arrayMgr.IsDupe(i))              // if it's a dupe
  1041.             arrayMgr.UpdateDupes(i,tempOffset);  // update all of them
  1042.         else
  1043.             arrayMgr[i]->offset = tempOffset;
  1044.         tempOffset += size;                 // set for next location in Tempfile
  1045.         }    
  1046.  
  1047.     GlobalUnlock(hMem);
  1048.     GlobalFree(hMem);
  1049.     arrayMgr.LastOffset(tempOffset);
  1050.     UpdateHeader(TempFile);
  1051.     TempFile.Close();                       // close 'em
  1052.     StackFile.Close();
  1053.     StackFile.Delete();                     // delete the old guy
  1054.     TempFile.Rename(StackFile.GetName());   // rename the disk file
  1055.     StackFile.Open(OF_READWRITE);           // re-open it     
  1056. #endif
  1057.     }
  1058.     
  1059. void ClipStac::Init(void)
  1060.     {
  1061.     myCursor(WAIT);
  1062.         // initialize list box here...
  1063.     if(newFile)
  1064.         {
  1065.         arrayMgr.Init(MaxItems);
  1066.         UpdateHeader(StackFile);
  1067.         newFile = FALSE;
  1068.         }
  1069.     else                    // read array table from existing file
  1070.         {
  1071.             // go to array table offset
  1072.         StackFile.ReadAt(0L,sizeof(header),&header);
  1073.         arrayMgr.Init(header.MaxElements);   // create array buffer and init maxEl
  1074.         arrayMgr.SetNumElements(header.NumElements); // init numEl
  1075.         arrayMgr.LastOffset(header.LastOffset);     // init lastoffset
  1076.                                     // read the array table into array
  1077.         StackFile.ReadAt(0L+sizeof(header),
  1078.             (WORD)arrayMgr.Size(),arrayMgr.Array());
  1079.  
  1080.         if(arrayMgr.MaxElements() != MaxItems)  // if array needs resizing
  1081.             ResizeFileHeader();                        //  do it.
  1082.         if(bAutoPack)             // if compression turned on
  1083.             PackFile();          // do it.
  1084.         InitListBox();
  1085.         }
  1086.     clp.JoinViewers();    // become part of Clipboard chain
  1087.     myCursor(ARROW);
  1088.     }
  1089.  
  1090. void ClipStac::DeleteItems(void)
  1091.     {
  1092.     while(SendDlgItemMessage(hWnd,IDM_LISTBOX,LB_DELETESTRING,0,0L) > 0)
  1093.         ;
  1094.     }
  1095.  
  1096. void ClipStac::InitListBox(void)
  1097.     {
  1098.     int i;
  1099.     CLIPOBJECT clobj;
  1100.     for(i = arrayMgr.NumElements()-1; i >= 0; i--)
  1101.         {
  1102.         StackFile.ReadAt(arrayMgr[i]->offset,
  1103.             sizeof(CLIPOBJECT),&clobj);
  1104.         if((SendDlgItemMessage(hWnd,IDM_LISTBOX,LB_INSERTSTRING,
  1105.                 0,(LONG)(LPSTR)clobj.name)) < 0)
  1106.             {
  1107.             MessageBox(hWnd,"Unable to insert data into List Box!",szAppName,MB_OK);
  1108.             break;
  1109.             }
  1110.         }
  1111.     }
  1112.  
  1113. void ClipStac::WMSYSCOMMAND(WinAppMsg& m)
  1114.     {
  1115.     switch(m.wParam)
  1116.         {
  1117.         case SC_ABOUT:
  1118.             {
  1119.             lbItems = SendMessage(ListBoxHdl,LB_GETCOUNT,0,0L);
  1120. #if defined(__BORLANDC__)
  1121.             DialogBox(GetInstance(), "ABOUTBOX", hWnd, (FARPROC)DialogProc);
  1122. #else
  1123.             FARPROC lpDlgProc = MakeProcInstance((FARPROC)DialogProc,GetInstance());
  1124.             DialogBox(GetInstance(), "ABOUTBOX", hWnd, lpDlgProc);
  1125.             FreeProcInstance(lpDlgProc);
  1126. #endif
  1127.             break;
  1128.             }
  1129.         case SC_AUTOLOAD:
  1130.             AutoLoad();
  1131.             break;
  1132.         case SC_AUTOPACK:
  1133.             bAutoPack = !bAutoPack;
  1134.             break;
  1135.         default:
  1136.             DefWinProc(m);
  1137.             break;
  1138.         }
  1139.     }
  1140.  
  1141. int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int)
  1142.     {
  1143.     myCursor(WAIT);
  1144.     ClipStac MyWin(szAppName);
  1145.     if(MyWin.GetPrevInstance())
  1146.         {
  1147.         myCursor(ARROW);
  1148.         MessageBox(NULL,"ClipStac already running!",szAppName,MB_OK);
  1149.         return 0;
  1150.         }
  1151.     MyWin.Display();                    // open the window
  1152.     myCursor(ARROW);
  1153.     return MyWin.Run();                 // process any messages
  1154.     }
  1155.  
  1156.  
  1157.